﻿using System.Text.RegularExpressions;
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.Data.SQLite;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using WebLog.Db;
using System.Threading;
using WebLog.Db.Update;
using System.Collections.Concurrent;
using System.Text;
using System.Data;
using WebLog.Extends;

namespace WebLog
{
    public static class WebLogHelper
    {
        static WebLogHelper()
        {
            Thread.CurrentThread.Name = Comm.MainThreadName;
            StatusHandel.Start();
        }

        /// <summary>
        /// 当前数据库最新的版本
        ///  更新执行时赋值
        /// </summary>
        private static double curLastVersion;//最大版本

        internal static string curVersion = "";//数据库版本
        private static SQLiteHelper sqliteHelper;

        /// <summary>
        /// 锁定（保证每次必要的数据库操作是原子级）
        /// </summary>
        private static object lockObj = new object();

        #region 任务集合

        private static void GetAndSend(string exePath, string dbPath, string controllerName)
        {
            System.Diagnostics.Process p = new System.Diagnostics.Process();
            p.StartInfo.FileName = "cmd.exe";
            p.StartInfo.UseShellExecute = false;    //是否使用操作系统shell启动
            p.StartInfo.RedirectStandardInput = true;//接受来自调用程序的输入信息
            p.StartInfo.RedirectStandardOutput = true;//由调用程序获取输出信息
            p.StartInfo.RedirectStandardError = true;//重定向标准错误输出
            p.StartInfo.CreateNoWindow = true;//不显示程序窗口
            p.Start();//启动程序

            //向cmd窗口发送输入信息
            string cmdStr = "";
            if (!controllerName.ToLower().Contains("/api/"))
            {
                controllerName = $"/api/{controllerName}/ -Method=GET";
            }
            p.StandardInput.WriteLine(cmdStr = (string.Format("{0} -dbFilePath={1} -Path={2}", exePath, dbPath, controllerName) + " &exit"));
            p.StandardInput.AutoFlush = true;
            //p.StandardInput.WriteLine("exit");
            //向标准输入写入要执行的命令。这里使用&是批处理命令的符号，表示前面一个命令不管是否执行成功都执行后面(exit)命令，如果不执行exit命令，后面调用ReadToEnd()方法会假死
            //同类的符号还有&&和||前者表示必须前一个命令执行成功才会执行后面的命令，后者表示必须前一个命令执行失败才会执行后面的命令
            Task.Run(() =>
            {
                var r = p.StandardOutput.ReadToEndAsync().Result;
                p.WaitForExit();//等待程序执行完退出进程
                p.Close();
            });
        }

        private static void KillGetAndSendExe()
        {
            try
            {
                foreach (var thisproc in System.Diagnostics.Process.GetProcessesByName("GetAndSend_PY2"))
                {
                    if (!thisproc.CloseMainWindow())
                    {
                        thisproc.Kill();
                    }
                }
            }
            catch (System.Exception ex)
            {
                //
            }
        }

        #region 启动后的任务

        private static async Task DecodePath()
        {
            KillGetAndSendExe();
            //var sql =
            //@"--得到所有网站前缀
            //        SELECT LOWER(substr(Path,1,rootIdx)) RootUrl
            //        from (
            //         SELECT (protIdx + instr(substr(Path,protIdx, pLen), '/') - 2) rootIdx, pLen, Path
            //         from (
            //          select LENGTH(Path) pLen, instr(Path, ':') protIdx,path
            //          from weblog
            //          GROUP BY path
            //         )
            //        ) a
            //        GROUP BY RootUrl
            //        ORDER BY RootUrl;
            //        --得到所有方法
            //        SELECT substr(Path,rootIdx + 1,pLen) ControllerStr
            //        from (
            //         SELECT (protIdx + instr(substr(Path,protIdx, pLen), '/') - 2) rootIdx, pLen, Path
            //         from (
            //          select LENGTH(Path) pLen, instr(Path, ':') protIdx,path
            //          from weblog
            //                Where Complete>10
            //          GROUP BY path
            //         )
            //        )b
            //        GROUP BY ControllerStr
            //        ORDER BY ControllerStr;";
            //var ds = sQLiteHelper.GetDataSet(sql);
            var currentAssembly = System.Reflection.Assembly.GetExecutingAssembly();
            var helperExe = Path.GetDirectoryName(currentAssembly.Location) + "\\Web\\tool\\GetAndSend_PY2.exe";
            if (!File.Exists(helperExe)) return;
            var dbName = Path.GetDirectoryName(currentAssembly.Location);
            var curName = "Enterprise.Web";
            dbName = dbName.Substring(0, dbName.IndexOf(curName) + curName.Length) + "\\" + SQLiteHelper.dbName;
            /* 在这里执行这个可以使得网页刚启动就运行这些api
            GetAndSend(helperExe, dbName, "Product");
            GetAndSend(helperExe, dbName, "/api/Apply/GetListByPages");
            GetAndSend(helperExe, dbName, "ItemCheck");
             */
            GetAndSend(helperExe, dbName, "Product");
            GetAndSend(helperExe, dbName, "/api/Apply/GetListByPages");
            GetAndSend(helperExe, dbName, "ItemCheck");
        }

        #endregion 启动后的任务

        #endregion 任务集合

        public static Config Config { get => _Config ?? GetConfig(); }

        #region 配置相关

        /// <summary>
        /// 程序配置
        /// </summary>
        private static Config _Config;

        public static object SetConfig(ConfigInputDto config)
        {
            if (!config.WriteOpen.HasValue && !config.ReadOpen.HasValue)
                return GetConfig();
            bool dateChange = false;//时间阈值缩小时 要重置删除时间
            if (config.WriteOpen.HasValue)
            {
                _Config.WriteOpen = config.WriteOpen.Value;
            }
            if (config.ReadOpen.HasValue)
            {
                _Config.ReadOpen = config.ReadOpen.Value;
            }
            if (config.OkDate.HasValue)
            {
                if (config.OkDate < 0.5m) return "最小保留月份为0.5个月";
                if (_Config.OkDate - config.OkDate.Value > 0) dateChange = true;
                _Config.OkDate = config.OkDate.Value;
            }
            if (config.ErrDate.HasValue)
            {
                if (config.ErrDate < 0.5m) return "最小保留月份为0.5个月";
                if (_Config.ErrDate - config.ErrDate.Value > 0) dateChange = true;
                _Config.ErrDate = config.ErrDate.Value;
            }
            if (dateChange)
            {
                Comm.repository.Set<DateTime?>("lastDeleteTime", null);
            }
            Comm.repository.Set("WebLogConfig", _Config);
            return GetConfig();
        }

        private static Config GetConfig()
        {
            var config = Comm.repository.Get<Config>("WebLogConfig", null);
            if (config == null)//历史数据处理
            {
                var oldConfig = new Config();
                DataTable dt = new DataTable();
                Comm.TryRun(() =>
                    dt = sqliteHelper.GetDataTable("select * from config limit 0,1"));
                if (dt.Rows.Count > 0)
                {
                    var dr = dt.Rows[0];
                    oldConfig.WriteOpen = bool.Parse(dr["WriteOpen"].ToString());
                    oldConfig.ReadOpen = bool.Parse(dr["ReadOpen"].ToString());
                    oldConfig.OkDate = decimal.Parse(dr["OkDate"].ToString());
                    oldConfig.ErrDate = decimal.Parse(dr["ErrDate"].ToString());
                }
                else//没有配置表数据的情况下
                {
                    oldConfig.ReadOpen = true;
                    oldConfig.WriteOpen = true;
                    oldConfig.OkDate = 3;
                    oldConfig.ErrDate = 6;
                }
                config = _Config = oldConfig;
                if (!Comm.repository.Set("WebLogConfig", oldConfig))
                {
                    StatusWait.VerifyStatus(WebLogStatus.TimerNotRun, () => Comm.repository.Set("WebLogConfig", oldConfig));
                }
            }
            else _Config = config;
            if (_Config.WriteOpen) StatusHandel.timerStart();
            else StatusHandel.timerStop();
            return config;
        }
        /// <summary>
        /// 手工指定db的物理路径，如果为空，则会取当前运行目录
        /// </summary>
        public static void SetDbPath (string path)
        {
            sqliteHelper = SQLiteHelper.GetInstance();
            sqliteHelper.dbPath = path;
        }
        #endregion 配置相关

        #region 数据库升级及初始数据准备

        /// <summary>
        /// 判断并创建默认表
        /// </summary>
        /// <param name="isReset">是否重置（表结构变更时）</param>
        private static async Task updateDatabase(bool isReset = false)
        {
            if (isReset)
            {
                await sqliteHelper.ExecuteNonQueryAsync(@"
                    DROP TABLE if exists Edition;
                    DROP TABLE if exists weblog;");
                Comm.TryRun(() =>//遗留的配置表 用不到了
                    sqliteHelper.ExecuteNonQuery(@"DROP TABLE if exists Config;"));
                await AppendSysLog("重置数据库执行完成");
            }//config 表已废弃 使用心得 键值对表 自由灵活
            await sqliteHelper.ExecuteNonQueryAsync(@"
                create table if not exists weblog(
                id integer PRIMARY KEY autoincrement,                -- 设置主键
                Path VARCHAR(500),Success BOOLEAN,ContentType VARCHAR(100),Headers TEXT,IsHttps BOOLEAN,Method VARCHAR(20),
                Date DATETIME,Body TEXT,Query TEXT,Data TEXT,Message TEXT
                );
                create table if not exists Edition(
                id integer PRIMARY KEY autoincrement,                -- 设置主键
                V double,
                Memo VARCHAR(500),--版本简介
                Date DATETIME--更新版本的时间
                );");
            var dt = sqliteHelper.GetDataTable("select * from Edition ORDER BY V DESC");
            if (dt.Rows.Count == 0)//重置 因为没有任何的版本
            {
                if (isReset == false)
                {
                    await updateDatabase(true);
                    return;
                }
                else//处于重置状态
                {
                    await sqliteHelper.ExecuteNonQueryAsync($"insert into Edition(V,Memo) values({1},'1.0版本创建')", true);
                    dt = sqliteHelper.GetDataTable("select * from Edition ORDER BY V DESC");
                }
            }
            curVersion = dt.Rows[0]["V"].ToString();
            //后面把这里改成反射获取类并add
            List<baseUpdateDatabase> vTasks = new List<baseUpdateDatabase>();
            var baseType = typeof(baseUpdateDatabase);
            vTasks.AddRange(
                baseType.Assembly.GetTypes().Where(e => e.IsSubclassOf(baseType)).Select(e => baseType.Assembly.CreateInstance(e.FullName)).OfType<baseUpdateDatabase>()
                );//把所有继承baseUpdateDatabase 的类加进来
            curLastVersion = vTasks.Max(e => e.V);
            if (dt.Select($"V={curLastVersion}").Count() == 0)
            {
                try
                {
                    await _DeleteLog(7);
                }
                catch (Exception ex)
                {
                    await AppendSysLog("删除日志失败" + ex.Message);
                }
                await AppendSysLog("数据库需要升级");
                bool isUpdated = false;
                foreach (var task in vTasks.OrderBy(e => e.V))//逐版本向上升级
                {
                    if (dt.Rows.Count > 0 && dt.Select($"V={task.V}").Count() == 0)//版本里面没有key版本的时候
                    {
                        try
                        {
                            await AppendSysLog("数据库升级准备中：V" + task.V);
                            await task.UpdateAction();//执行里面的任务 成功之后加增一条记录
                            curVersion = task.V.ToString();
                            /*Memo VARCHAR(500),--版本简介
                        Date DATETIME--更新版本的时间*/
                            SQLiteParameter[] sQLiteParameters = new SQLiteParameter[3];
                            sQLiteParameters[0] = new SQLiteParameter("V", task.V);
                            sQLiteParameters[1] = new SQLiteParameter("Memo", task.Memo);
                            sQLiteParameters[2] = new SQLiteParameter("Date", DateTime.Now);
                            if (curVersion == "2") await sqliteHelper.ExecuteNonQueryAsync($"insert into Edition(V) values(@V)", true, sQLiteParameters);
                            else await sqliteHelper.ExecuteNonQueryAsync($"insert into Edition(V,Memo,Date) values(@V,@Memo,@Date)", true, sQLiteParameters);
                            isUpdated = true;
                            await AppendSysLog("数据库升级成功");
                        }
                        catch (Exception)
                        {
                            await AppendSysLog("数据库升级失败：V" + task.V);
                            await updateDatabase();//重新升级 出错的话
                            return;
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 在启动更新前需要准备的查询的数据
        /// </summary>
        /// <returns></returns>
        private static async Task initDatas()
        {
            try
            {
                string temp_store_directory = "";
                while ((temp_store_directory = sqliteHelper.ExecuteScalar("PRAGMA temp_store_directory;")).IsNullEmpty())
                {
                    var dir = System.Environment.CurrentDirectory;
                    dir = dir.Substring(0, dir.IndexOf(":")) + ":\\tmp";
                    if (!Directory.Exists(dir)) Directory.CreateDirectory(dir);
                    sqliteHelper.ExecuteScalar($"PRAGMA temp_store_directory='{dir}';");
                }
                Db.SqlLogHelpers.LogSqlPathConfigHelper.GetAndLoadLogPaths();
                GetConfig();
            }
            catch (Exception ex)
            {
                AppendSysLog("初始化db数据失败了！" + ex.Message);
            }
        }

        #endregion 数据库升级及初始数据准备

        /// <summary>
        /// 程序状态 属性
        /// </summary>
        private static WebLogStatus? Status
        {
            get
            {
                return _status;
            }
            set
            {
                if (value == _status) return;
                var oldStatus = _status;
                lock (lockObj)
                    _status = value;
                WebLogStatusChangeHandle.ChangeStatusPush(oldStatus, value);
                if (oldStatus == WebLogStatus.TimerNotRun && value == WebLogStatus.TimerOneRuning//定时器运行状态会来回切换 不做记录
                    || oldStatus == WebLogStatus.TimerOneRuning && value == WebLogStatus.TimerNotRun) return;
                AppendSysLog(string.Format("状态已变更:{0} => {1}",
                    oldStatus.HasValue ? oldStatus.ToString() : "空",
                    value.HasValue ? value.ToString() : "空"));
            }
        }

        #region 状态 事件

        internal static WebLogStatus? GetStatus()
            => Status;

        /// <summary>
        /// 程序状态仓库
        /// </summary>
        private static WebLogStatus? _status;

        #endregion 状态 事件

        //增设定时任务定时新增队列里的日志

        #region 删除旧日志

        private const int AllowDelNotHandelLogCount = 360;//360次连续无请求就可以执行删除了
        private static DateTime? lastDeleteTime;

        internal static object GetLastDeleteTime(bool isRunDelete = false)
        {
            if (isRunDelete)
            {
                StatusWait.WaitStatus(WebLogStatus.TimerNotRun);
                var result = DeleteLog();//尝试手动删除日志
                result.Wait();
                return result.Result;
            }
            return lastDeleteTime;
        }

        /// <summary>
        /// 触发器及其他调用删除日志的包装
        /// </summary>
        /// <param name="days"></param>
        /// <returns></returns>
        private static async Task<bool> DeleteLog()
        {
            bool isRunDel = false;
            if ((lastDeleteTime == null || (DateTime.Now - lastDeleteTime.Value).TotalDays >= 1))//一天跑一次删除
            {
                lock (lockObj)
                {
                    Status = WebLogStatus.TimerRunPause;
                }
                var dTask = _DeleteLog();
                dTask.Wait();
                isRunDel = dTask.Result;
                lock (lockObj)
                {
                    Status = WebLogStatus.TimerRunPauseEnd;//暂停结束
                }
            }
            return isRunDel;
        }

        private static Task DeleteUnnecessaryLog()
        {
            dynamic alllogs = SearchLog(new SearchLogInputDto()
            {
                BeginTime = DateTime.Now.Date.AddDays(-1),
                EndTime = DateTime.Now.Date.AddSeconds(-1),
                PageSkipClose = true,
                Success = true,
                VerifyStatus = false,
                OrderField = OrderFields.Date,
                IsDesc = true,
            });
            if (alllogs.rows is DataTable)
            {
                DataTable dt = alllogs.rows;
                Dictionary<string, List<int>> pathNeedDeleteIds = new Dictionary<string, List<int>>();
                var defPathTakeCount = Comm.repository.Get<int>("defPathTakeCount", 1000);
                var pathDayTakeCount = Comm.repository.Get<Dictionary<string, int>>("pathDayTakeCount", new Dictionary<string, int>());
                foreach (DataRow dr in dt.Rows)
                {
                    var path = dr["Path"].ToString();
                    if (path.IsNullEmpty()) continue;
                    if (!pathNeedDeleteIds.ContainsKey(path)) pathNeedDeleteIds.Add(path, new List<int>());
                    pathNeedDeleteIds[path].Add(int.Parse(dr["id"].ToString()));
                }
                var keys = pathNeedDeleteIds.Keys.ToArray();
                var UnnecessaryKeys = new List<string>();
                List<int> needDeleteIds = new List<int>();
                foreach (var key in keys)
                {
                    var idlist = pathNeedDeleteIds[key];
                    int takeCount = defPathTakeCount;
                    if (pathDayTakeCount.ContainsKey(key)) takeCount = pathDayTakeCount[key];
                    idlist = pathNeedDeleteIds[key] = idlist.Except(idlist.Take(takeCount)).ToList();//选择前N条 然后用大集合减去他 得到要删除的
                    needDeleteIds.AddRange(idlist);
                    if (idlist.Count > 0)
                        UnnecessaryKeys.Add(key);
                }
                if (needDeleteIds.Count > 0)
                {
                    AppendSysLog(string.Format("路径[{0}]的请求数量已经超过预设条数被自动清除了，默认预设{1}条"
                        , string.Join('、', UnnecessaryKeys), defPathTakeCount));
                    var sql = "delete from weblog where id in (" + string.Join(',', needDeleteIds) + ");";
                    return sqliteHelper.ExecuteNonQueryAsync(sql, true);
                }
            }
            return Task.Delay(1);
        }

        //删除一个月没有用到的 查询历史
        private static Task DeleteSearchLogHistoryids()
        {
            var dic = Comm.repository.Get<Dictionary<Guid, DateTime>>("SearchLogHistoryids", new Dictionary<Guid, DateTime>());
            if (dic.Values.Any(e => (DateTime.Now.Date - e.Date).TotalDays > 30))
            {
                var deleteKeySql = string.Join(';', dic.Where(e => (DateTime.Now.Date - e.Value.Date).TotalDays > 30).Select(e => $"delete from KeyValues where (Key='SearchLogHistory_{e.Key}')"));
                deleteKeySql += ";" + string.Join(';', dic.Where(e => (DateTime.Now.Date - e.Value.Date).TotalDays > 30).Select(e => $"delete from KeyValues where (Key='dates_searchLogInputDto_{e.Key}')"));
                if (!deleteKeySql.IsNullEmpty())
                    return sqliteHelper.ExecuteNonQueryAsync(deleteKeySql, true);
            }
            return Task.Delay(1);
        }

        /// <summary>
        /// 删除日志的代码要做到前向后兼容 否则会产生异常
        /// 因为升级版本前检测了删除时间
        /// </summary>
        /// <param name="days"></param>
        /// <returns></returns>
        private static async Task<bool> _DeleteLog(int? days = null)
        {
            bool isRunDel = false;
            var dbdeleteTime = Comm.repository.Get<DateTime?>("lastDeleteTime");
            if (dbdeleteTime == null || (DateTime.Now - dbdeleteTime.Value).TotalDays >= (!days.HasValue ? 1 : days.Value))
            {
                try
                {
                    lastDeleteTime = DateTime.Now;
                    await AppendSysLog("陈旧日志清理开始");
                    await DeleteUnnecessaryLog();
                    await DeleteSearchLogHistoryids();
                    //删除的代码
                    var _commandStr = @"
                    delete from logSqls where logId in (
                        select id from weblog where (Success=1 and Date<@okDate) or (Success=0 and Date<@errDate)
                        );
                    delete from weblog where (Success=1 and Date<@okDate) or (Success=0 and Date<@errDate);
                    delete from SysLog where Date<@okDate;";
                    SQLiteParameter[] sQLiteParameters = new SQLiteParameter[2];
                    int okM = (int)(Config.OkDate);
                    double okD = (int)((Config.OkDate - okM) * 30);//按照一个月30天来
                    int errM = (int)(Config.ErrDate);
                    double errD = (int)((Config.ErrDate - errM) * 30);//按照一个月30天来
                    sQLiteParameters[0] = new SQLiteParameter("okDate", lastDeleteTime.Value.Date.AddMonths(-1 * okM).AddDays(-1 * okD));
                    sQLiteParameters[1] = new SQLiteParameter("errDate", lastDeleteTime.Value.Date.AddMonths(-1 * errM).AddDays(-1 * errD));
                    System.Threading.Thread.Sleep(500);
                    await sqliteHelper.ExecuteNonQueryAsync(_commandStr, true, sQLiteParameters);
                    await AppendSysLog("陈旧日志清理完成；开始VACUUM");
                    System.Threading.Thread.Sleep(500);
                    await sqliteHelper.ExecuteNonQueryAsync("VACUUM;", false);//VACUUM指令尽量不执行
                    System.Threading.Thread.Sleep(500);
                    await AppendSysLog("完成VACUUM");
                    if (!Comm.repository.Set("lastDeleteTime", lastDeleteTime))
                        StatusWait.VerifyStatus(WebLogStatus.TimerNotRun, () =>
                        {
                            Comm.repository.Set("lastDeleteTime", lastDeleteTime);
                        });
                    isRunDel = true;
                }
                catch (Exception ex)
                {
                    lastDeleteTime = null;
                    AppendSysLog("删除日志异常" + ex.Message);
                    isRunDel = false;
                }
            }
            else lastDeleteTime = dbdeleteTime;
            return isRunDel;
        }

        #endregion 删除旧日志

        public static void AddOrUpdateLog(WebReqLog log, bool isUpdate = false)
        {
            if (!Config.WriteOpen) return;
            if (!isUpdate)
                _nothasIdLogs.Enqueue(log);
            else
                _hasIdNotCompletedLogs.Equals(log);
        }

        //更新日志
        public static void CompleteLog(WebReqLog log, bool isSuccess, string Data, string Message = null)
        {
            log.Complete = (DateTime.Now - log.Date).TotalSeconds;
            log.Success = isSuccess;
            log.Data = Data;
            log.Message = log.Message;
            if (log.id.HasValue)
            {
                //update 逻辑
            }
        }

        private static ConcurrentQueue<WebReqLog> Logs { get => _nothasIdLogs; }

        private static ConcurrentQueue<WebReqLog> _nothasIdLogs;
        private static ConcurrentQueue<WebReqLog> _hasIdNotCompletedLogs;

        #region 查询接口

        //查询sql
        internal static object SearchSqlLog(int weblogID)
        {
            string commandStr = @"select * from logSqls where
                            logId=@ID";
            var dt = sqliteHelper.GetDataTable(commandStr, sQLiteParameters: new[] { new SQLiteParameter("ID", weblogID) });
            var sqls = new List<object>();
            foreach (System.Data.DataRow row in dt.Rows)
                sqls.Add(new { id = row["id"], sql = row["sqlStr500"].ToString() + row["sqlStr"] });
            return sqls;
        }

        //查询日志
        public static object SearchLog(SearchLogInputDto searchLogInputDto)
        {
            if (searchLogInputDto.VerifyStatus)
            {
                if (Status == WebLogStatus.TimerRunPause)
                    return Comm.TypeFactory.CreateBaseBizResult("日志服务暂停中，可能原因：正在自动删除陈旧日志并整理空间大小！");
                if (Status < WebLogStatus.Runed)
                    return Comm.TypeFactory.CreateBaseBizResult("日志服务还未启动，可能原因：正在升级数据结构中！");
            }
            string commandStr = @"select * from weblog where";
            string orderStr = "";
            if (searchLogInputDto.Node != null)
            {
                var whereStr = searchLogInputDto.Node.GetUnions();
                if (whereStr.IsNullEmpty()) commandStr += " 1=1";
                else
                {
                    if (whereStr.ToLower().Contains("delete ") || whereStr.ToLower().Contains("update ") || whereStr.ToLower().Contains("drop ") || whereStr.ToLower().Contains("where "))
                        return Comm.TypeFactory.CreateBaseBizResult("禁止包含敏感字符delete|update|drop|where");
                    commandStr += " " + whereStr;
                }
                orderStr += "ORDER BY id Desc";//id正常情况下就是时间序列的
            }
            else
            {
                commandStr += @"
                            (@ID is null or @ID=0 or id=@ID) and
                            (@BeginTime is null or @BeginTime='' or date>@BeginTime) and
                            (@EndTime is null or @EndTime='' or date<@EndTime) and
                            (@Path='%%' or Path like @Path) and
                            (@ContentType='%%' or ContentType like @ContentType) and
                            (@Headers='%%' or Headers like @Headers) and
                            (@Query='%%' or Query like @Query) and
                            (@Body='%%' or Body like @Body) and
                            (@Data='%%' or Data like @Data) and
                            (@Message='%%' or Message like @Message) and
                            (@Method='%%' or Method like @Method) and
                            (@RealName='%%' or RealName like @RealName) and
                            (@Success is null or @Success='' or Success=@Success) and
                            (@CompleteBegin is null or @CompleteBegin='' or Complete>@CompleteBegin) and
                            (@CompleteEnd is null or @CompleteEnd='' or Complete<@CompleteEnd) and
                            1=1 ";//0-1000条
                if (searchLogInputDto.OrderField.HasValue)
                    orderStr += $"ORDER BY {searchLogInputDto.OrderField.ToString()} {(searchLogInputDto.IsDesc ? "Desc" : "")}";
                else orderStr += "ORDER BY id Desc";//id正常情况下就是时间序列的
            }
            if (!searchLogInputDto.PageSkipClose)
                orderStr += @"
                        limit @Skip,@Take";
            SQLiteParameter[] sQLiteParameters = new SQLiteParameter[22];
            int j = 0;
            sQLiteParameters[j++] = new SQLiteParameter("ID", searchLogInputDto.ID);
            sQLiteParameters[j++] = new SQLiteParameter("BeginTime", searchLogInputDto.BeginTime);
            sQLiteParameters[j++] = new SQLiteParameter("EndTime", searchLogInputDto.EndTime);
            sQLiteParameters[j++] = new SQLiteParameter("Path", "%" + (searchLogInputDto.Path ?? "") + "%");
            sQLiteParameters[j++] = new SQLiteParameter("ContentType", "%" + (searchLogInputDto.ContentType ?? "") + "%");
            sQLiteParameters[j++] = new SQLiteParameter("Headers", "%" + (searchLogInputDto.Headers ?? "") + "%");
            sQLiteParameters[j++] = new SQLiteParameter("Query", "%" + (searchLogInputDto.Query ?? "") + "%");
            sQLiteParameters[j++] = new SQLiteParameter("Body", "%" + (searchLogInputDto.Body ?? "") + "%");
            sQLiteParameters[j++] = new SQLiteParameter("Data", "%" + (searchLogInputDto.Data ?? "") + "%");
            sQLiteParameters[j++] = new SQLiteParameter("Message", "%" + (searchLogInputDto.Message ?? "") + "%");
            sQLiteParameters[j++] = new SQLiteParameter("Method", "%" + (searchLogInputDto.Method ?? "") + "%");
            sQLiteParameters[j++] = new SQLiteParameter("RealName", "%" + (searchLogInputDto.RealName ?? "") + "%");
            sQLiteParameters[j++] = new SQLiteParameter("CompleteBegin", searchLogInputDto.CompleteBegin);
            sQLiteParameters[j++] = new SQLiteParameter("CompleteEnd", searchLogInputDto.CompleteEnd);
            sQLiteParameters[j++] = new SQLiteParameter("Success", searchLogInputDto.Success);

            //页码处理
            searchLogInputDto.Skip = searchLogInputDto.CurrentPageIndex * searchLogInputDto.PageSize;
            searchLogInputDto.Take = searchLogInputDto.PageSize;
            sQLiteParameters[j++] = new SQLiteParameter("Skip", searchLogInputDto.Skip);
            sQLiteParameters[j++] = new SQLiteParameter("Take", searchLogInputDto.Take);
            var dt = sqliteHelper.GetDataTable(commandStr + orderStr, sQLiteParameters: sQLiteParameters);
            var totalStr = sqliteHelper.GetDataTable(commandStr.Replace("select *", "select count(*)"), sQLiteParameters: sQLiteParameters).Rows[0][0].ToString();
            searchLogInputDto.AllSql = commandStr + orderStr;
            if (!searchLogInputDto.IsNotRecord)
                Extends.SearchExtend.AppendSearchLogDto(searchLogInputDto);
            dt.Columns.Add("Completed", typeof(bool));
            foreach (var dr in dt.Select("Complete=0 or Complete is null"))
                dr["Completed"] = false;
            foreach (var dr in dt.Select("Complete>0"))
                dr["Completed"] = true;
            return new { total = int.Parse(totalStr), rows = dt };
        }

        #endregion 查询接口

        private static Task AppendSysLog(string msg, string v = null)
            => Comm.sysLogHelper.AppendSysLog(msg, v ?? curVersion);

        public static string parseHeaders(string headers)
        {
            if (string.IsNullOrEmpty(headers)) return "无身份信息";
            int idx = headers.IndexOf("ck_userrealname=");
            if (idx == -1) return "无身份信息";
            headers = headers.Substring(idx);
            var names = headers.Substring(0, headers.IndexOf(';'));
            names = System.Web.HttpUtility.UrlDecode(names);
            var realName = names.Split('=').Last();
            idx = headers.IndexOf("ck_userid=");
            if (idx == -1) return "无身份信息";
            headers = headers.Substring(idx);
            var ids = headers.Substring(0, headers.IndexOf(';'));
            var uid = ids.Split('=').Last();
            return realName + "---" + uid;
        }

        public static class StatusWait
        {
            /// <summary>
            /// 等待状态变更时执行的方法集合
            /// </summary>
            private static ConcurrentDictionary<WebLogStatus, ConcurrentQueue<Action>> waitStatusChangeActions = new ConcurrentDictionary<WebLogStatus, ConcurrentQueue<Action>>();

            static StatusWait()
            {
                WebLogStatusChangeHandle.Add((e) =>
                {
                    var value = e.newStatus;
                    if (value.HasValue)
                    {
                        try
                        {
                            var curVal = value.Value;
                            if (waitStatusChangeActions.ContainsKey(curVal))
                            {
                                Action run;
                                while (waitStatusChangeActions[curVal].TryDequeue(out run))
                                {
                                    Task.Run(run).Wait();//执行注册在里面的方法
                                }
                                ConcurrentQueue<Action> actions;
                                waitStatusChangeActions.Remove(curVal, out actions);
                            }
                        }
                        catch (Exception ex)
                        {
                            Comm.sysLogHelper.AppendSysLog("执行状态变更事件异常" + ex.Message);
                        }
                    }
                });
            }

            /// <summary>
            /// 禁止使用能循环很多次的代码进入这种模块
            /// </summary>
            /// <param name="needStatus"></param>
            /// <param name="okCall"></param>
            /// <returns></returns>
            internal static bool VerifyStatus(WebLogStatus needStatus, Action okCall)
            {
                if (!WebLogHelper.GetStatus().HasValue || WebLogHelper.GetStatus() < needStatus)
                {
                    waitStatusChangeActions.TryAdd(needStatus, new ConcurrentQueue<Action>());
                    waitStatusChangeActions[needStatus].Enqueue(okCall);
                    return false;
                }
                else return true;
            }

            /// <summary>
            /// 禁止使用能循环很多次的代码进入这种模块
            /// 验证状态
            /// 小于需求状态时
            ///     等待状态变更为需求状态 并通知当前等待线程
            ///     如果主线程waitOne就会死锁
            ///         这种情况请使用上面的方法
            ///         例 if(!WebLogHelper.WaitStatus(WebLogStatus.TimerNotRun, () => DeffAndChangeLogPaths(paths))) return;
            ///             第二个参数是达到预期时执行的代码        如果返回true可以直接往下执行
            /// </summary>
            /// <param name="needStatus"></param>
            internal static void WaitStatus(WebLogStatus needStatus)
            {
                if (Comm.IsMainThread()) throw Comm.TypeFactory.CreateBizException("主线程不可以调用此方法 会陷入死锁");
                if (!WebLogHelper.GetStatus().HasValue || WebLogHelper.GetStatus() < needStatus)
                {
                    var are = new AutoResetEvent(false);
                    waitStatusChangeActions.TryAdd(needStatus, new ConcurrentQueue<Action>());
                    waitStatusChangeActions[needStatus].Enqueue(() => are.Set());
                    are.WaitOne();
                }
            }
        }

        //内部状态变化推手
        private static class StatusHandel
        {
            static StatusHandel()
            {
                WebLogStatusChangeHandle.Add((e) =>
                {
                    var value = e.newStatus;
                    try
                    {
                        switch (value)
                        {
                            case WebLogStatus.StartBefore:
                                StartBefore();
                                break;

                            case WebLogStatus.Started:
                                Started();
                                break;

                            case WebLogStatus.RunBefore:
                                RunBefore();
                                break;

                            case WebLogStatus.Runed:
                                Runed();
                                break;

                            case WebLogStatus.TimerNotRun://触发器状态
                                break;

                            case WebLogStatus.TimerOneRuning://触发器状态
                                break;

                            case WebLogStatus.TimerRunPause://暂停定时器
                                TimerRunPause();
                                break;

                            case WebLogStatus.TimerRunPauseEnd://结束暂停
                                TimerRunPauseEnd();
                                break;

                            case WebLogStatus.End:
                                break;

                            default:
                                break;
                        }
                    }
                    catch (Exception ex)
                    {
                        AppendSysLog(string.Format("状态异常:{0} => {1}，{2}",
                        e.oldStatus.HasValue ? e.oldStatus.ToString() : "空",
                        value.HasValue ? value.ToString() : "空"), ex.Message);
                    }
                });
            }

            #region 事件

            static internal void Start()
                => Status = WebLogStatus.StartBefore;

            /// <summary>
            /// 启动前
            /// </summary>
            private static async Task StartBefore()
            {
                try
                {
                    await Task.Delay(1500);
                    _nothasIdLogs = new ConcurrentQueue<WebReqLog>();
                    _hasIdNotCompletedLogs = new ConcurrentQueue<WebReqLog>();
                    sqliteHelper = SQLiteHelper.GetInstance();
                    await sqliteHelper.ExecuteNonQueryAsync(@"
                create table if not exists SysLog(
                V double,
                Date DATETIME,
                MSG VARCHAR(1000)
                );");
                    //定时写日志
                    timer = new System.Timers.Timer();
                    timer.Enabled = false;
                    timerInterval = 5;
                    timer.Interval = 1000 * timerInterval;//执行间隔时间,单位为毫秒
                    timer.Elapsed += Timer_Elapsed;
                    Status = WebLogStatus.Started;
                }
                catch (Exception ex)
                {
                    AppendSysLog("启动时异常" + ex.Message + "..................." + ex.StackTrace);
                    throw ex;
                }
            }

            /// <summary>
            /// 启动后
            /// </summary>
            private static async Task Started()
            {
                await initDatas();
                await updateDatabase();//更新数据库
                                       //if (sqliteHelper.GetDataTable("select count(*) from config").Rows[0][0].ToString().Equals("0"))
                                       //    sqliteHelper.ExecuteNonQuery("insert into Config(WriteOpen,ReadOpen,OkDate,ErrDate) values(0, 0, 3, 6)");
                Status = WebLogStatus.RunBefore;
            }

            /// <summary>
            /// 运行前
            /// </summary>
            private static async void RunBefore()
            {
                timerStart();//打开定时器
                if (!Config.WriteOpen)//如果此时没有开启写权限 清空
                {
                    Logs.Clear();
                }
                Status = WebLogStatus.Runed;
            }

            /// <summary>
            /// 运行后
            /// </summary>
            private static async void Runed()
            {
#if RELEASE
            //DecodePath();
#endif
                Status = WebLogStatus.TimerNotRun;
            }

            /// <summary>
            /// 定时器暂停
            /// </summary>
            private static async void TimerRunPause()
            {
                timerStop();//暂停
            }

            /// <summary>
            /// 定时器结束暂停
            /// </summary>
            private static async void TimerRunPauseEnd()
            {
                timerStart();//打开定时器
                Status = WebLogStatus.TimerNotRun;//回到未运行状态
            }

            #endregion 事件

            /// <summary>
            /// 定时器
            /// </summary>
            private static System.Timers.Timer timer;

            #region 定时器事件

            /// <summary>
            /// 定时器间隔 （S）
            /// </summary>
            private static int timerInterval;

            internal static void timerStart()
            {
                if (_Config != null && !_Config.WriteOpen)//不允许写入
                {
                    AppendSysLog("未开启写入权限！");
                    return;
                }
                if (curVersion != curLastVersion + "")
                {
                    AppendSysLog("不是最新版本数据库，故无法启动！");
                    return;
                }
                //运行前之后的状态才能启动
                if (!timer.Enabled && Status >= WebLogStatus.RunBefore)
                {
                    timer.Start();
                    AppendSysLog("定时器已打开");
                }
            }

            internal static void timerStop()
            {
                if (timer.Enabled)
                {
                    Timer_Elapsed(null, null);//立即记录
                    timer.Stop();
                    AppendSysLog("定时器已停止");
                }
            }

            /// <summary>
            /// 准备处理log将其写入数据库时
            /// </summary>
            /// <param name="rowCount"></param>
            private static bool BeginHandelLog()
            {
                var curRunCount = _nothasIdLogs.Count;
                if (continuousNotHandelLogCount < AllowDelNotHandelLogCount)
                {
                    //不允许删除时
                    if (curRunCount != lastRunCount) continuousNotHandelLogCount = 0;//归零 每一次logs 的数量发生改变的话就进行归零
                    else continuousNotHandelLogCount++;//累加
                }
                if (continuousNotHandelLogCount >= AllowDelNotHandelLogCount || (DateTime.Now.Hour >= 2 && DateTime.Now.Hour <= 4))//2~4点的话也走删除的逻辑
                {
                    if (Status >= WebLogStatus.TimerNotRun)
                        if (lastDeleteTime == null || (DateTime.Now - lastDeleteTime.Value).Days >= 1)//最后删除时间比现在大时
                        {
                            DeleteLog();
                            return false;
                        }
                }
                lastRunCount = curRunCount;
                return true;
            }

            private static volatile int lastRunCount = 0;//最后一次的请求处理数
            private static volatile int continuousNotHandelLogCount = 0;//连续的未处理请求的次数
            private static decimal SqlWarnTimeNum = 0;//语句预警时间

            /// <summary>
            /// 记录sql前调用
            /// </summary>
            /// <param name="_sql"></param>
            /// <returns>返回false就不记录</returns>
            private static bool beforeWriteSql(string path, string _sql)
            {
                if (_sql.IndexOf("Executed DbCommand (") == 0)//得到秒数
                {
                    var _timeStr = _sql.Replace("Executed DbCommand (", "");
                    _timeStr = _timeStr.Substring(0, _timeStr.IndexOf("ms) [Parameters=["));
                    if (SqlWarnTimeNum <= 0)
                        SqlWarnTimeNum = Comm.repository.Get<decimal>("SqlWarnTimeNum", 800);
                    decimal _time = -1m, warnNum = SqlWarnTimeNum;
                    if (warnNum <= 0) warnNum = 800;
                    if (decimal.TryParse(_timeStr, out _time) && _time > warnNum)//暂时定义为超过2s的发出警告吧
                    {
                        var cur_sql = "\r\n\r\n--" + new Regex("@__ef_filter__IsSoftDeleteFilterEnabled_\\d+")
                            .Replace(_sql, "1");

                        string msg = string.Format("{0}的sql执行，运行耗时[{1}ms]，超过了预设的警告阈值[{2}ms]", path, _time, warnNum);
                        EMailExtend.SendEmail("语句运行超时", msg + "\r\n\r\n语句内容\r\n" + cur_sql + Comm.GetLinkStrByPath(path));
                        //console.warn('--' + r.sql.replace(/@__ef_filter__IsSoftDeleteFilterEnabled_\d+/g, '1'));
                        Comm.TypeFactory.SendMsg(msg);
                    }
                }
                return true;
            }

            private static bool firstAdd = true;

            private static void HandlerLogSqls(WebReqLog curLog, List<KeyValuePair<StringBuilder, KeyValuePair<WebReqLog, List<SQLiteParameter>>>> sqls, ref int ref_j, ref int ref__j)
            {
                if (curLog == null || curLog.Sqls == null || curLog.Sqls.Count < 1 || sqls == null) return;
                var curLogSqls = curLog.Sqls;
                List<SQLiteParameter> sQLiteParameters = new List<SQLiteParameter>(); StringBuilder _commandStr = new StringBuilder();
                int j = ref_j, _j = ref__j;
                Action<object, bool> _addParameter = (val, isLast) =>//这里会把所有的参数替换成原本顺序的参数
                {
                    sQLiteParameters.Add(new SQLiteParameter("p" + j, val));
                    _commandStr = _commandStr.Replace("@p" + _j + (isLast ? ")" : ","), "@p" + j + (isLast ? ")" : ","));
                    _j++; j++;
                };
                int sqlIdx = 0;
                foreach (var _sql in curLogSqls)
                {
                    sqlIdx++;
                    if (_sql.IndexOf("Executing DbCommand ") == 0)
                    {
                        var sqlfind = _sql.Substring(_sql.IndexOf("[Parameters=["));
                        if (curLogSqls.Skip(sqlIdx).Any(s =>
                        {
                            if (s.IndexOf("Executed DbCommand (") != 0) return false;
                            return sqlfind.Equals(s.Substring(s.IndexOf("[Parameters=[")));
                        })) continue;//在这条日志之后 有日志是执行完成且完全与自己一致 那么 这条日志不写入数据库
                    }
                    if (!beforeWriteSql(curLog.Path, _sql)) continue;
                    _j = 0;//重新从0开始计数
                    sQLiteParameters = new List<SQLiteParameter>();
                    _commandStr = new StringBuilder();
                    _commandStr.Append(@"insert into logSqls(logId,SQLStr500,SQLStr)
                        values(@p0,@p1,@p2);");
                    _addParameter(curLog.id.Value, false);
                    _addParameter(_sql.Length > 500 ? _sql.Substring(0, 500) : _sql, false);
                    _addParameter(_sql.Length > 500 ? _sql.Substring(500) : null, true);
                    sqls.Add(new KeyValuePair<StringBuilder, KeyValuePair<WebReqLog, List<SQLiteParameter>>>(_commandStr, new KeyValuePair<WebReqLog, List<SQLiteParameter>>(curLog, sQLiteParameters)));
                }
                ref_j = j; ref__j = _j;//把变更写回去
                int maxSqlCount = 30;
                if (curLogSqls.Count / 2 > maxSqlCount)
                    EMailExtend.SendEmail("方法内部包含的sql，超过预警数", $"\r\n\r\n{curLog.Path} sql数 {curLogSqls.Count / 2};超过了预设数{maxSqlCount}\r\n" + Comm.GetLinkStrByPath(curLog.Path));
            }

            private static void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs eArgs)
            {
                lock (lockObj)
                {
                    if (Status != WebLogStatus.TimerNotRun)
                    {
                        return;
                    }
                    var allowHandel = BeginHandelLog();
                    if (!allowHandel)
                    {
                        AppendSysLog("BeginHandelLog False");
                        return;//不允许执行时跳出 可能是触发了暂停等等
                    }
                    Status = WebLogStatus.TimerOneRuning;
                    if (firstAdd)
                        AppendSysLog("首次添加日志开始");
                    firstAdd = false;
                }

                int j = 0;
                long nextId = 1;
                var sqls = new List<KeyValuePair<StringBuilder, KeyValuePair<WebReqLog, List<SQLiteParameter>>>>();
                WebReqLog curLog;
                if (_nothasIdLogs.Count > 0)//待新增队列
                {
                    var idDt = sqliteHelper.GetDataTable("select id+1 from weblog ORDER BY id DESC LIMIT 0,1");
                    if (idDt?.Rows?.Count > 0) long.TryParse(idDt.Rows[0][0].ToString(), out nextId);
                }
                //先读取id
                while (_nothasIdLogs.TryDequeue(out curLog))//理论上这里的都没有id
                {
                    StringBuilder _commandStr = new StringBuilder();
                    var sQLiteParameters = new List<SQLiteParameter>();
                    sqls.Add(new KeyValuePair<StringBuilder, KeyValuePair<WebReqLog, List<SQLiteParameter>>>(_commandStr, new KeyValuePair<WebReqLog, List<SQLiteParameter>>(curLog, sQLiteParameters)));
                    curLog.id = nextId++;
                    _commandStr.Append(@"insert into weblog(ID,Path,ContentType,Headers,IsHttps,Method,Date,Body,Query,RealName,Complete,Success,Message,Data)
            values(@p0,@p1,@p2,@p3,@p4,@p5,@p6,@p7,@p8,@p9,@p10,@p11,@p12,@p13);");
                    int _j = 0;
                    Action<object, bool> addParameter = (val, isLast) =>//这里会把所有的参数替换成原本顺序的参数
                    {
                        sQLiteParameters.Add(new SQLiteParameter("p" + j, val));
                        _commandStr = _commandStr.Replace("@p" + _j + (isLast ? ")" : ","), "@p" + j + (isLast ? ")" : ","));
                        _j++; j++;
                    };
                    addParameter(curLog.id.Value, false);
                    addParameter(curLog.Path, false);
                    addParameter(curLog.ContentType, false);
                    addParameter(curLog.Headers, false);
                    addParameter(curLog.IsHttps, false);
                    //5
                    addParameter(curLog.Method, false);
                    addParameter(curLog.Date, false);
                    addParameter(curLog.Body, false);
                    addParameter(curLog.Query, false);
                    try
                    {
                        curLog.RealName = parseHeaders(curLog.Headers);
                    }
                    catch (Exception ex)
                    {
                        AppendSysLog("处理名字失败" + ex.Message);
                    }
                    addParameter(curLog.RealName, false);
                    //10
                    lock (curLog)//锁定这个对象 因为在读取他的完成度
                    {
                        addParameter(curLog.Completed ? (object)curLog.Complete : null, false);
                        //没完成的日志加进去都是null打头
                        addParameter(curLog.Completed ? (object)curLog.Success : null, false);
                        addParameter(curLog.Completed ? (object)curLog.Message : null, false);
                        addParameter(curLog.Completed ? (object)curLog.Data : null, true);
                        if (!curLog.Completed)
                            _hasIdNotCompletedLogs.Enqueue(curLog);
                        else//已完成的就处理掉日志
                            HandlerLogSqls(curLog, sqls, ref j, ref _j);
                    }
                }
                List<WebReqLog> notHandles = new List<WebReqLog>();
                while (_hasIdNotCompletedLogs.TryDequeue(out curLog))
                {
                    if (!curLog.id.HasValue) throw new Exception("此容器只装未进入数据库的日志");
                    lock (curLog)
                    {
                        if (!curLog.Completed)//没完成就放进去下次循环的时候再来处理
                        {
                            notHandles.Add(curLog);
                            continue;
                        }
                    }
                    StringBuilder _commandStr = new StringBuilder(@"update weblog
                        set Success=@p0,Message=@p1,Data=@p2,Complete=@p3,Date=Date
                        where id=@p4;");
                    var sQLiteParameters = new List<SQLiteParameter>();
                    sqls.Add(new KeyValuePair<StringBuilder, KeyValuePair<WebReqLog, List<SQLiteParameter>>>(_commandStr, new KeyValuePair<WebReqLog, List<SQLiteParameter>>(curLog, sQLiteParameters)));
                    //已有插入数据库的id 且是完成状态 执行update

                    int _j = 0;
                    Action<object, bool> addParameter = (val, isLast) =>//这里会把所有的参数替换成原本顺序的参数
                    {
                        if (_j > 10)
                        {
                            throw new Exception("当前方法的替换规则不可以超过10！");
                        }
                        sQLiteParameters.Add(new SQLiteParameter("p" + j, val));
                        _commandStr = _commandStr.Replace("@p" + _j + (isLast ? ";" : ","), "@p" + j + (isLast ? ";" : ","));
                        _j++; j++;
                    };
                    addParameter(curLog.Success, false);
                    addParameter(curLog.Message, false);
                    addParameter(curLog.Data, false);
                    addParameter(curLog.Complete, false);
                    addParameter(curLog.id.Value, true);
                    HandlerLogSqls(curLog, sqls, ref j, ref _j);
                }
                notHandles.ForEach(e => _hasIdNotCompletedLogs.Enqueue(e));
                if (sqls.Count > 0)
                {
                    string sqlPrefix = "", sqlEnd = "";
                    bool isNeedPage = false;
                    if (isNeedPage)
                    {
                        int size = 9;//分页执行 避免参数过多之类的情况
                        for (int i = 0; i < (sqls.Count / size) + (sqls.Count % size == 0 ? 0 : 1); i++)
                        {
                            var curSqls = sqls.Skip(i * size).Take(size).ToList();
                            var _sqls = string.Join(";", curSqls.Select(el => el.Key.ToString()));
                            var sqlps = curSqls.SelectMany(el => el.Value.Value).ToArray();
                            try
                            {
                                sqliteHelper.ExecuteNonQuery(sqlPrefix + _sqls + sqlEnd, true, sqlps);
                            }
                            catch (Exception ex)
                            {
                                AppendSysLog($"insert执行失败" + ex.Message);
                                if (ex.Message?.ToLower()?.Contains("unique constraint failed") == true)
                                    AppendSysLog("系统错误：产生了重复的id！");//异常情况 不允许发生的情况
                                foreach (var _log in curSqls.Select(el => el.Value.Key).Where(e => e != null).Distinct())
                                {//回滚并回到队列
                                    if (_log.id.HasValue)
                                        _hasIdNotCompletedLogs.Enqueue(_log);
                                    else
                                        _nothasIdLogs.Enqueue(_log);
                                }
                            }
                        }
                    }
                    else
                    {
                        var _sqls = string.Join(";", sqls.Select(el => el.Key));
                        var sqlps = sqls.SelectMany(el => el.Value.Value).ToArray();
                        try
                        {
                            sqliteHelper.ExecuteNonQuery(sqlPrefix + _sqls + sqlEnd, true, sqlps);
                        }
                        catch (Exception ex)
                        {
                            AppendSysLog($"insert执行失败" + ex.Message);//UNIQUE constraint failed 针对唯一约束失败的处理
                            if (ex.Message?.ToLower()?.Contains("unique constraint failed") == true)
                                AppendSysLog("系统错误：产生了重复的id！");//异常情况 不允许发生的情况
                            foreach (var _log in sqls.Select(el => el.Value.Key).Where(e => e != null).Distinct())
                            {//回滚并回到队列
                                if (_log.id.HasValue)
                                    _hasIdNotCompletedLogs.Enqueue(_log);
                                else
                                    _nothasIdLogs.Enqueue(_log);
                            }
                            Status = WebLogStatus.TimerNotRun;
                        }
                    }
                }
                lock (lockObj)
                {
                    Status = WebLogStatus.TimerNotRun;
                }
            }

            #endregion 定时器事件
        }
    }
}